package bll

import (
	log "auth/collector/logger"
	"auth/errors"
	"auth/event"
	"auth/model"
	"auth/model/entity"
	"auth/store"
	"auth/store/postgres"
	"context"
	"gorm.io/gorm"
	"time"
)

type api struct {
	iApi    store.IApi
	iCasbin store.ICasbin
}

var Api = &api{}

func (a *api) init() func() {
	a.iApi = postgres.Api
	a.iCasbin = postgres.CasbinService
	return func() {}
}

func (a *api) onEvent(*event.Data) {}

func (a *api) Create(ctx context.Context, in *model.ApiCreateRequest) error {
	var (
		err  error
		info = &model.ApiInfo{}
	)
	info.Path = in.Path
	info.Method = in.Method
	if _, err = a.iApi.FindByParameter(info); !errors.Is(err, gorm.ErrRecordNotFound) {
		return errors.DeptExistApi.Error()
	}
	c := buildApi(in)
	_, err = a.iApi.Create(c)
	return err
}

func (a *api) Update(ctx context.Context, in *model.ApiUpdateRequest) error {
	var (
		err  error
		dict = make(map[string]interface{})
		info = &model.ApiInfo{}
		oldA *entity.Api
	)
	oldA, err = a.iApi.Find(in.ID)
	if err != nil {
		log.Error(err)
		return err
	}
	if oldA.ID <= 0 {
		return errors.ParameterErr.Error()
	}
	if oldA.Path != in.Path || oldA.Method != in.Method {
		info.Path = in.Path
		info.Method = in.Method
		if _, err = a.iApi.FindByParameter(info); !errors.Is(err, gorm.ErrRecordNotFound) {
			return errors.DeptExistApi.Error()
		}
	}
	err = a.iCasbin.UpdateCasbinApi(oldA.Path, in.Path, oldA.Method, in.Method)
	if err != nil {
		return err
	}
	dict["path"] = in.Path
	dict["method"] = in.Method
	dict["api_group"] = in.ApiGroup
	dict["description"] = in.Description
	dict["updated_at"] = time.Now().Unix()
	return a.iApi.Update(in.ID, dict)
}

func (a *api) Delete(ctx context.Context, in *model.ApiDeleteRequest) error {
	d, err := a.iApi.Find(in.ID)
	if err != nil || d.ID <= 0 { // api记录不存在
		return errors.NoData.Error()
	}
	success := CasbinService.ClearCasbin(1, d.Path, d.Method)
	if !success {
		return errors.New(d.Path + ":" + d.Method + "casbin同步清理失败")
	}
	e := CasbinService.Casbin()
	err = e.InvalidateCache()
	if err != nil {
		return err
	}
	return a.iApi.Delete(in.ID)
}

func (a *api) List(ctx context.Context, in *model.ApiListRequest) (*model.ApiListResponse, error) {
	var (
		err   error
		total int
		list  []*entity.Api
		out   = &model.ApiListResponse{}
	)

	if total, list, err = a.iApi.List(in); err != nil {
		return nil, err
	}

	out.Total = total
	out.Data = model.ApisEntityToDto(list)

	return out, err
}

func (a *api) GetAllApis(ctx context.Context) (*model.GetAllApisResponse, error) {
	var (
		err  error
		out  = &model.GetAllApisResponse{}
		apis []*entity.Api
	)
	apis, err = a.iApi.GetAllApis()
	if err != nil {
		return nil, err
	}
	out.Data = model.ApisEntityToDto(apis)
	return out, err
}

func buildApi(in *model.ApiCreateRequest) *entity.Api {
	return &entity.Api{

		Path: in.Path,

		Description: in.Description,

		ApiGroup: in.ApiGroup,

		Method: in.Method,

		CreatedAt: time.Now().Unix(),

		UpdatedAt: time.Now().Unix(),
	}
}
